home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 2 / AACD 2.iso / AACD / Magazine / GraphicsCards / StormMesa / src / texobj.c < prev    next >
C/C++ Source or Header  |  1999-02-04  |  18KB  |  640 lines

  1. /* $Id: texobj.c,v 3.5 1998/04/20 23:55:13 brianp Exp $ */
  2.  
  3. /*
  4.  * Mesa 3-D graphics library
  5.  * Version:  2.8
  6.  * Copyright (C) 1995-1998  Brian Paul
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU Library General Public
  10.  * License as published by the Free Software Foundation; either
  11.  * version 2 of the License, or (at your option) any later version.
  12.  *
  13.  * This library is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * Library General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Library General Public
  19.  * License along with this library; if not, write to the Free
  20.  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  */
  22.  
  23.  
  24. /*
  25.  * $Log: texobj.c,v $
  26.  * Revision 3.5  1998/04/20 23:55:13  brianp
  27.  * applied DavidB's changes for v0.25 of 3Dfx driver
  28.  *
  29.  * Revision 3.4  1998/03/27 04:17:31  brianp
  30.  * fixed G++ warnings
  31.  *
  32.  * Revision 3.3  1998/02/27 00:53:52  brianp
  33.  * fixed a few incorrect error messages
  34.  *
  35.  * Revision 3.2  1998/02/20 04:53:37  brianp
  36.  * implemented GL_SGIS_multitexture
  37.  *
  38.  * Revision 3.1  1998/02/03 04:27:54  brianp
  39.  * added texture lod clamping
  40.  *
  41.  * Revision 3.0  1998/01/31 21:04:38  brianp
  42.  * initial rev
  43.  *
  44.  */
  45.  
  46.  
  47. #ifdef PC_HEADER
  48. #include "all.h"
  49. #else
  50. #include <assert.h>
  51. #include <stdio.h>
  52. #include <stdlib.h>
  53. #include "context.h"
  54. #include "hash.h"
  55. #include "macros.h"
  56. #include "teximage.h"
  57. #include "texobj.h"
  58. #include "types.h"
  59. #endif
  60.  
  61.  
  62.  
  63. /*
  64.  * Allocate a new texture object and add it to the linked list of texture
  65.  * objects.  If name>0 then also insert the new texture object into the hash
  66.  * table.
  67.  * Input:  shared - the shared GL state structure to contain the texture object
  68.  *         name - integer name for the texture object
  69.  *         dimensions - either 1, 2 or 3
  70.  * Return:  pointer to new texture object
  71.  */
  72. struct gl_texture_object *
  73. gl_alloc_texture_object( struct gl_shared_state *shared, GLuint name,
  74.                          GLuint dimensions)
  75. {
  76.    struct gl_texture_object *obj;
  77.  
  78.    assert(dimensions <= 3);
  79.  
  80.    obj = (struct gl_texture_object *)
  81.                      calloc(1,sizeof(struct gl_texture_object));
  82.    if (obj) {
  83.       /* init the non-zero fields */
  84.       obj->Name = name;
  85.       obj->Dimensions = dimensions;
  86.       obj->WrapS = GL_REPEAT;
  87.       obj->WrapT = GL_REPEAT;
  88.       obj->MinFilter = GL_NEAREST_MIPMAP_LINEAR;
  89.       obj->MagFilter = GL_LINEAR;
  90.       obj->MinLod = -1000.0;
  91.       obj->MaxLod = 1000.0;
  92.       obj->BaseLevel = 0;
  93.       obj->MaxLevel = 1000;
  94.       obj->MinMagThresh = 0.0F;
  95.       obj->Palette[0] = 255;
  96.       obj->Palette[1] = 255;
  97.       obj->Palette[2] = 255;
  98.       obj->Palette[3] = 255;
  99.       obj->PaletteSize = 1;
  100.       obj->PaletteIntFormat = GL_RGBA;
  101.       obj->PaletteFormat = GL_RGBA;
  102.  
  103.       /* insert into linked list */
  104.       if (shared) {
  105.          obj->Next = shared->TexObjectList;
  106.          shared->TexObjectList = obj;
  107.       }
  108.  
  109.       if (name > 0) {
  110.          /* insert into hash table */
  111.          HashInsert(shared->TexObjects, name, obj);
  112.       }
  113.    }
  114.    return obj;
  115. }
  116.  
  117.  
  118. /*
  119.  * Deallocate a texture object struct and remove it from the given
  120.  * shared GL state.
  121.  * Input:  shared - the shared GL state to which the object belongs
  122.  *         t - the texture object to delete
  123.  */
  124. void gl_free_texture_object( struct gl_shared_state *shared,
  125.                              struct gl_texture_object *t )
  126. {
  127.    struct gl_texture_object *tprev, *tcurr;
  128.  
  129.    assert(t);
  130.  
  131.    /* unlink t from the linked list */
  132.    if (shared) {
  133.       tprev = NULL;
  134.       tcurr = shared->TexObjectList;
  135.       while (tcurr) {
  136.          if (tcurr==t) {
  137.             if (tprev) {
  138.                tprev->Next = t->Next;
  139.             }
  140.             else {
  141.                shared->TexObjectList = t->Next;
  142.             }
  143.             break;
  144.          }
  145.          tprev = tcurr;
  146.          tcurr = tcurr->Next;
  147.       }
  148.    }
  149.  
  150.    if (t->Name) {
  151.       /* remove from hash table */
  152.       HashRemove(shared->TexObjects, t->Name);
  153.    }
  154.  
  155.    /* free texture image */
  156.    {
  157.       GLuint i;
  158.       for (i=0;i<MAX_TEXTURE_LEVELS;i++) {
  159.          if (t->Image[i]) {
  160.             gl_free_texture_image( t->Image[i] );
  161.          }
  162.       }
  163.    }
  164.    /* free this object */
  165.    free( t );
  166. }
  167.  
  168.  
  169.  
  170. /*
  171.  * Examine a texture object to determine if it is complete or not.
  172.  * The t->Complete flag will be set to GL_TRUE or GL_FALSE accordingly.
  173.  */
  174. void gl_test_texture_object_completeness( struct gl_texture_object *t )
  175. {
  176.    t->Complete = GL_TRUE;  /* be optimistic */
  177.  
  178.    /* Always need level zero image */
  179.    if (!t->Image[0] || !t->Image[0]->Data) {
  180.       t->Complete = GL_FALSE;
  181.       return;
  182.    }
  183.  
  184.    /* Compute number of mipmap levels */
  185.    if (t->Dimensions==1) {
  186.       t->P = t->Image[0]->WidthLog2;
  187.    }
  188.    else if (t->Dimensions==2) {
  189.       t->P = MAX2(t->Image[0]->WidthLog2, t->Image[0]->HeightLog2);
  190.    }
  191.    else if (t->Dimensions==3) {
  192.       GLint max = MAX2(t->Image[0]->WidthLog2, t->Image[0]->HeightLog2);
  193.       max = MAX2(max, (GLint)(t->Image[0]->DepthLog2));
  194.       t->P = max;
  195.    }
  196.  
  197.    /* Compute M (see the 1.2 spec) used during mipmapping */
  198.    t->M = (GLfloat) (MIN2(t->MaxLevel, t->P) - t->BaseLevel);
  199.  
  200.  
  201.    if (t->MinFilter!=GL_NEAREST && t->MinFilter!=GL_LINEAR) {
  202.       /*
  203.        * Mipmapping: determine if we have a complete set of mipmaps
  204.        */
  205.       GLint i;
  206.       GLint minLevel = t->BaseLevel;
  207.       GLint maxLevel = MIN2(t->MaxLevel, MAX_TEXTURE_LEVELS-1);
  208.  
  209.       if (minLevel > maxLevel) {
  210.          t->Complete = GL_FALSE;
  211.          return;
  212.       }
  213.  
  214.       /* Test dimension-independent attributes */
  215.       for (i = minLevel; i <= maxLevel; i++) {
  216.          if (t->Image[i]) {
  217.             if (!t->Image[i]->Data) {
  218.                t->Complete = GL_FALSE;
  219.                return;
  220.             }
  221.             if (t->Image[i]->Format != t->Image[0]->Format) {
  222.                t->Complete = GL_FALSE;
  223.                return;
  224.             }
  225.             if (t->Image[i]->Border != t->Image[0]->Border) {
  226.                t->Complete = GL_FALSE;
  227.                return;
  228.             }
  229.          }
  230.       }
  231.  
  232.       /* Test things which depend on number of texture image dimensions */
  233.       if (t->Dimensions==1) {
  234.          /* Test 1-D mipmaps */
  235.          GLuint width = t->Image[0]->Width2;
  236.          for (i=1; i<MAX_TEXTURE_LEVELS; i++) {
  237.             if (width>1) {
  238.                width /= 2;
  239.             }
  240.             if (i >= minLevel && i <= maxLevel) {
  241.                if (!t->Image[i]) {
  242.                   t->Complete = GL_FALSE;
  243.                   return;
  244.                }
  245.                if (!t->Image[i]->Data) {
  246.                   t->Complete = GL_FALSE;
  247.                   return;
  248.                }
  249.                if (t->Image[i]->Width2 != width ) {
  250.                   t->Complete = GL_FALSE;
  251.                   return;
  252.                }
  253.             }
  254.             if (width==1) {
  255.                return;  /* found smallest needed mipmap, all done! */
  256.             }
  257.          }
  258.       }
  259.       else if (t->Dimensions==2) {
  260.          /* Test 2-D mipmaps */
  261.          GLuint width = t->Image[0]->Width2;
  262.          GLuint height = t->Image[0]->Height2;
  263.          for (i=1; i<MAX_TEXTURE_LEVELS; i++) {
  264.             if (width>1) {
  265.                width /= 2;
  266.             }
  267.             if (height>1) {
  268.                height /= 2;
  269.             }
  270.             if (i >= minLevel && i <= maxLevel) {
  271.                if (!t->Image[i]) {
  272.                   t->Complete = GL_FALSE;
  273.                   return;
  274.                }
  275.                if (t->Image[i]->Width2 != width) {
  276.                   t->Complete = GL_FALSE;
  277.                   return;
  278.                }
  279.                if (t->Image[i]->Height2 != height) {
  280.                   t->Complete = GL_FALSE;
  281.                   return;
  282.                }
  283.                if (width==1 && height==1) {
  284.                   return;  /* found smallest needed mipmap, all done! */
  285.                }
  286.             }
  287.          }
  288.       }
  289.       else if (t->Dimensions==3) {
  290.          /* Test 3-D mipmaps */
  291.          GLuint width = t->Image[0]->Width2;
  292.          GLuint height = t->Image[0]->Height2;
  293.          GLuint depth = t->Image[0]->Depth2;
  294.          for (i=1; i<MAX_TEXTURE_LEVELS; i++) {
  295.             if (width>1) {
  296.                width /= 2;
  297.             }
  298.             if (height>1) {
  299.                height /= 2;
  300.             }
  301.             if (depth>1) {
  302.                depth /= 2;
  303.             }
  304.             if (i >= minLevel && i <= maxLevel) {
  305.                if (!t->Image[i]) {
  306.                   t->Complete = GL_FALSE;
  307.                   return;
  308.                }
  309.                if (t->Image[i]->Width2 != width) {
  310.                   t->Complete = GL_FALSE;
  311.                   return;
  312.                }
  313.                if (t->Image[i]->Height2 != height) {
  314.                   t->Complete = GL_FALSE;
  315.                   return;
  316.                }
  317.                if (t->Image[i]->Depth2 != depth) {
  318.                   t->Complete = GL_FALSE;
  319.                   return;
  320.                }
  321.             }
  322.             if (width==1 && height==1 && depth==1) {
  323.                return;  /* found smallest needed mipmap, all done! */
  324.             }
  325.          }
  326.       }
  327.       else {
  328.          /* Dimensions = ??? */
  329.          gl_problem(NULL, "Bug in gl_test_texture_object_completeness\n");
  330.       }
  331.    }
  332. }
  333.  
  334.  
  335.  
  336. /*
  337.  * Execute glGenTextures
  338.  */
  339. void gl_GenTextures( GLcontext *ctx, GLsizei n, GLuint *texName )
  340. {
  341.    GLuint first;
  342.    GLint i;
  343.  
  344.    if (INSIDE_BEGIN_END(ctx)) {
  345.       gl_error( ctx, GL_INVALID_OPERATION, "glGenTextures" );
  346.       return;
  347.    }
  348.    if (n<0) {
  349.       gl_error( ctx, GL_INVALID_VALUE, "glGenTextures" );
  350.       return;
  351.    }
  352.  
  353.    first = HashFindFreeKeyBlock(ctx->Shared->TexObjects, n);
  354.  
  355.    /* Return the texture names */
  356.    for (i=0;i<n;i++) {
  357.       texName[i] = first + i;
  358.    }
  359.  
  360.    /* Allocate new, empty texture objects */
  361.    for (i=0;i<n;i++) {
  362.       GLuint name = first + i;
  363.       GLuint dims = 0;
  364.       (void) gl_alloc_texture_object(ctx->Shared, name, dims);
  365.    }
  366. }
  367.  
  368.  
  369.  
  370. /*
  371.  * Execute glDeleteTextures
  372.  */
  373. void gl_DeleteTextures( GLcontext *ctx, GLsizei n, const GLuint *texName)
  374. {
  375.    GLint i;
  376.  
  377.    if (INSIDE_BEGIN_END(ctx)) {
  378.       gl_error( ctx, GL_INVALID_OPERATION, "glDeleteTextures" );
  379.       return;
  380.    }
  381.  
  382.    for (i=0;i<n;i++) {
  383.       struct gl_texture_object *t;
  384.       if (texName[i]>0) {
  385.          t = (struct gl_texture_object *)
  386.             HashLookup(ctx->Shared->TexObjects, texName[i]);
  387.          if (t) {
  388.             GLuint texSet;
  389.             for (texSet=0; texSet<MAX_TEX_SETS; texSet++) {
  390.                struct gl_texture_set *set = &ctx->Texture.Set[texSet];
  391.                if (set->Current1D==t) {
  392.                   /* revert to default 1-D texture */
  393.                   set->Current1D = ctx->Shared->Default1D[texSet];
  394.                   t->RefCount--;
  395.                   assert( t->RefCount >= 0 );
  396.                }
  397.                else if (set->Current2D==t) {
  398.                   /* revert to default 2-D texture */
  399.                   set->Current2D = ctx->Shared->Default2D[texSet];
  400.                   t->RefCount--;
  401.                   assert( t->RefCount >= 0 );
  402.                }
  403.                else if (set->Current3D==t) {
  404.                   /* revert to default 3-D texture */
  405.                   set->Current3D = ctx->Shared->Default3D[texSet];
  406.                   t->RefCount--;
  407.                   assert( t->RefCount >= 0 );
  408.                }
  409.             }
  410.  
  411.             /* tell device driver to delete texture */
  412.             if (ctx->Driver.DeleteTexture) {
  413.                (*ctx->Driver.DeleteTexture)( ctx, t );
  414.             }
  415.  
  416.             if (t->RefCount==0) {
  417.                gl_free_texture_object(ctx->Shared, t);
  418.             }
  419.          }
  420.       }
  421.    }
  422. }
  423.  
  424.  
  425.  
  426. /*
  427.  * Execute glBindTexture
  428.  */
  429. void gl_BindTexture( GLcontext *ctx, GLenum target, GLuint texName )
  430. {
  431.    struct gl_texture_set *texSet = &ctx->Texture.Set[ctx->Texture.CurrentSet];
  432.    struct gl_texture_object *oldTexObj;
  433.    struct gl_texture_object *newTexObj;
  434.    struct gl_texture_object **targetPointer;
  435.    GLuint targetDimensions;
  436.  
  437.    if (INSIDE_BEGIN_END(ctx)) {
  438.       gl_error( ctx, GL_INVALID_OPERATION, "glBindTexture" );
  439.       return;
  440.    }
  441.    switch (target) {
  442.       case GL_TEXTURE_1D:
  443.          oldTexObj = texSet->Current1D;
  444.          targetPointer = &texSet->Current1D;
  445.          targetDimensions = 1;
  446.          break;
  447.       case GL_TEXTURE_2D:
  448.          oldTexObj = texSet->Current2D;
  449.          targetPointer = &texSet->Current2D;
  450.          targetDimensions = 2;
  451.          break;
  452.       case GL_TEXTURE_3D_EXT:
  453.          oldTexObj = texSet->Current3D;
  454.          targetPointer = &texSet->Current3D;
  455.          targetDimensions = 3;
  456.          break;
  457.       default:
  458.          gl_error( ctx, GL_INVALID_ENUM, "glBindTexture" );
  459.          return;
  460.    }
  461.  
  462.    if (texName==0) {
  463.       /* use default n-D texture */
  464.       switch (target) {
  465.          case GL_TEXTURE_1D:
  466.             newTexObj = ctx->Shared->Default1D[ctx->Texture.CurrentSet];
  467.             break;
  468.          case GL_TEXTURE_2D:
  469.             newTexObj = ctx->Shared->Default2D[ctx->Texture.CurrentSet];
  470.             break;
  471.          case GL_TEXTURE_3D_EXT:
  472.             newTexObj = ctx->Shared->Default3D[ctx->Texture.CurrentSet];
  473.             break;
  474.          default:
  475.             gl_problem(ctx, "Bad target in gl_BindTexture");
  476.             return;
  477.       }
  478.    }
  479.    else {
  480.       newTexObj = (struct gl_texture_object *)
  481.                              HashLookup(ctx->Shared->TexObjects, texName);
  482.       if (newTexObj) {
  483.          if (newTexObj->Dimensions == 0) {
  484.             /* first time bound */
  485.             newTexObj->Dimensions = targetDimensions;
  486.          }
  487.          else {
  488.             /* A small optimization */
  489.             if (newTexObj == oldTexObj)
  490.                return;
  491.  
  492.             if (newTexObj->Dimensions != targetDimensions) {
  493.                /* wrong dimensionality */
  494.                gl_error( ctx, GL_INVALID_OPERATION, "glBindTexture" );
  495.                return;
  496.             }
  497.          }
  498.       }
  499.       else {
  500.          /* create new texture object */
  501.          newTexObj = gl_alloc_texture_object(ctx->Shared, texName,
  502.                                              targetDimensions);
  503.       }
  504.    }
  505.  
  506.    /* Update the Texture.Current[123]D pointer */
  507.    *targetPointer = newTexObj;
  508.  
  509.    /* Tidy up reference counting */
  510.    if (*targetPointer != oldTexObj && oldTexObj->Name>0) {
  511.       /* decrement reference count of the prev texture object */
  512.       oldTexObj->RefCount--;
  513.       assert( oldTexObj->RefCount >= 0 );
  514.    }
  515.  
  516.    if (newTexObj->Name>0) {
  517.       newTexObj->RefCount++;
  518.    }
  519.  
  520.    /* Check if we may have to use a new triangle rasterizer */
  521.    if (   oldTexObj->WrapS != newTexObj->WrapS
  522.        || oldTexObj->WrapT != newTexObj->WrapT
  523.        || oldTexObj->WrapR != newTexObj->WrapR
  524.        || oldTexObj->MinFilter != newTexObj->MinFilter
  525.        || oldTexObj->MagFilter != newTexObj->MagFilter
  526.        || (oldTexObj->Image[0] && newTexObj->Image[0] && 
  527.           (oldTexObj->Image[0]->Format!=newTexObj->Image[0]->Format))
  528.        || !newTexObj->Complete) {
  529.       ctx->NewState |= NEW_RASTER_OPS;
  530.    }
  531.  
  532.    /* If we've changed the Current[123]D texture object then update the
  533.     * ctx->Texture.Current pointer to point to the new texture object.
  534.     */
  535.    if (oldTexObj == texSet->Current) {
  536.       texSet->Current = newTexObj;
  537.    }
  538.  
  539.    /* The current n-D texture object can never be NULL! */
  540.    assert(*targetPointer);
  541.  
  542.    /* Pass BindTexture call to device driver */
  543.    if (ctx->Driver.BindTexture) {
  544.       (*ctx->Driver.BindTexture)( ctx, target, newTexObj );
  545.    }
  546. }
  547.  
  548.  
  549.  
  550. /*
  551.  * Execute glPrioritizeTextures
  552.  */
  553. void gl_PrioritizeTextures( GLcontext *ctx,
  554.                             GLsizei n, const GLuint *texName,
  555.                             const GLclampf *priorities )
  556. {
  557.    GLint i;
  558.  
  559.    if (INSIDE_BEGIN_END(ctx)) {
  560.       gl_error( ctx, GL_INVALID_OPERATION, "glPrioritizeTextures" );
  561.       return;
  562.    }
  563.    if (n<0) {
  564.       gl_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" );
  565.       return;
  566.    }
  567.  
  568.    for (i=0;i<n;i++) {
  569.       struct gl_texture_object *t;
  570.       if (texName[i]>0) {
  571.          t = (struct gl_texture_object *)
  572.             HashLookup(ctx->Shared->TexObjects, texName[i]);
  573.          if (t) {
  574.             t->Priority = CLAMP( priorities[i], 0.0F, 1.0F );
  575.          }
  576.       }
  577.    }
  578. }
  579.  
  580.  
  581.  
  582. /*
  583.  * Execute glAreTexturesResident
  584.  */
  585. GLboolean gl_AreTexturesResident( GLcontext *ctx, GLsizei n,
  586.                                   const GLuint *texName,
  587.                                   GLboolean *residences )
  588. {
  589.    GLboolean resident = GL_TRUE;
  590.    GLint i;
  591.  
  592.    if (INSIDE_BEGIN_END(ctx)) {
  593.       gl_error( ctx, GL_INVALID_OPERATION, "glAreTexturesResident" );
  594.       return GL_FALSE;
  595.    }
  596.    if (n<0) {
  597.       gl_error( ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)" );
  598.       return GL_FALSE;
  599.    }
  600.  
  601.    for (i=0;i<n;i++) {
  602.       struct gl_texture_object *t;
  603.       if (texName[i]==0) {
  604.          gl_error( ctx, GL_INVALID_VALUE, "glAreTexturesResident(textures)" );
  605.          return GL_FALSE;
  606.       }
  607.       t = (struct gl_texture_object *)
  608.          HashLookup(ctx->Shared->TexObjects, texName[i]);
  609.       if (t) {
  610.          /* we consider all valid texture objects to be resident */
  611.          residences[i] = GL_TRUE;
  612.       }
  613.       else {
  614.          gl_error( ctx, GL_INVALID_VALUE, "glAreTexturesResident(textures)" );
  615.          return GL_FALSE;
  616.       }
  617.    }
  618.    return resident;
  619. }
  620.  
  621.  
  622.  
  623. /*
  624.  * Execute glIsTexture
  625.  */
  626. GLboolean gl_IsTexture( GLcontext *ctx, GLuint texture )
  627. {
  628.    if (INSIDE_BEGIN_END(ctx)) {
  629.       gl_error( ctx, GL_INVALID_OPERATION, "glIsTextures" );
  630.       return GL_FALSE;
  631.    }
  632.    if (texture>0 && HashLookup(ctx->Shared->TexObjects, texture)) {
  633.       return GL_TRUE;
  634.    }
  635.    else {
  636.       return GL_FALSE;
  637.    }
  638. }
  639.  
  640.